/*
 	Software Author: Mike Moore
 	Vectrics Flashrecruit
 	Open source job board and applicant tracking system.  Built with enterprise Java.
 */
package org.vectrics.struts;

import java.util.List;

import org.apache.ecs.html.A;
import org.apache.ecs.html.Input;
import org.apache.log4j.Logger;
import org.vectrics.SystemException;
import org.vectrics.common.html.Cell;
import org.vectrics.common.html.Form;
import org.vectrics.common.html.Row;
import org.vectrics.common.html.Table;
import org.vectrics.common.html.TextHelper;
import org.vectrics.common.pagelist.PageList;

public abstract class PageListTag extends VectricsTagSupport {

	private static final long serialVersionUID = 2055607967951171626L;
	
	private transient static Logger log = Logger.getLogger(PageListTag.class);
	public static String PAGE_PARAM = "page";
	private int currentPage = 0;	
	private boolean showVoided = false;
	private PageList pageList = null;
	private String width = "95%";
	private boolean showNextPrevAtTop = false;
	private int totalElementCount = 0;
	private boolean useGraphicButtons = false;
	
	protected void init() {
		log.debug("init() not implemented by derived class");
	}

	protected Form createForm() {
		return(null);
	}
	
	//protected abstract List getElements(int startIndex, int endIndex) throws VectricsException;
	//protected abstract int getTotalElementCount() throws VectricsException;
	
	protected abstract String getDescription();
	protected abstract String getPageListLink();
	
	/**
	 * Needs to be overridden if getForm() returns a real form.  
	 * @return
	 */
	protected String getFormAction() {
		return(null);
	}

	// Override in derived classes that need to set form properties or add hidden
	// inputs.
	protected void onFormCreate(Form form) {
	}
	
	protected String getNoElementsMessage() {
	    return(this.getPhrase("phrase.no.elements"));
	}
	
	abstract protected void showList(String description, 
			Cell mainCell, List elements, Form form);
	
	abstract protected PageList createPageList();
	
	protected final PageList getPageList() {
		log.debug("getPageList() - returns the pageList used to hold the list of data");
		if (pageList == null) {
			log.debug("getPageList() - creating pagelist");
			pageList = createPageList();
			totalElementCount = pageList.getTotalElementCount();
		}
		return(pageList);
	//	return(createPageList());
	}

	protected String makePageTopContent(String description) {
		if ((description != null) && (description.trim().length() > 0)) {
			return("<h2>"+ description + "</h2>");
		}
		else {
			return("");
		}
	}
	
	protected final int getTotalPages() {
		int pages = totalElementCount / getPageSize();
		if ((pages * getPageSize()) < totalElementCount) {
			pages++;
		}
		return(pages);		
	}

	
	public PageListTag() {
		super();
	}

	/**
	 * Returns true if the derived instance will use page listing (with previous and next button).
	 * @return true if instance will use page listing.
	 */
	protected boolean usePageListing() {
		return(true);
	}

	protected void fillBottomCell(Cell cell) {
	}

	public final int getCurrentPage() {
		return currentPage;
	}

	public final void setCurrentPage(int currentPage) {
		this.currentPage = currentPage;
	}

	public final int getPageSize() {
		return(getPageList().getPageSize());
	}

	public void setPageSize(int pageSize) {
		getPageList().setPageSize(pageSize);
	}


	protected final boolean hasNextPage() {
		log.debug("entering hasNextPage() - method to determine if"
				+ " there is a next page after the currently displayed one.");
		boolean result = false;
		int numberOfPages = getTotalPages();
		if (this.getCurrentPage() + 1 < numberOfPages) {
			result = true;
		}
		if (log.isDebugEnabled()) {
			log.debug("hasNextPage() - result 		 = " + result);
			log.debug("hasNextPage() - numberOfPages = " + numberOfPages);
			log.debug("hasNextPage() - currentPage   = " + this.getCurrentPage());
		}
		return(result);
	}	


	protected String getTopOfPageContent() {
		return("");
	}
    
	public final String makeStartTag()  {
		log.debug("doStartTag() - entered");
		init();
		pageList = null;
		pageList = this.getPageList();
		Table mainTable = new Table();
		
		Form form = this.createForm();
		
		if (form != null) {
			if (this.getFormAction() == null)
				throw new SystemException("Derived class defined a form, but did not define a getFormAction() " +
						"method, make this method return a real action");
			onFormCreate(form);
			form.setAction(this.getFormAction());
			form.addAttribute("name", this.getClass().getCanonicalName());
			String nextButtonParam = this.getRequest().getParameter("next.x");
			String previousButtonParam = this.getRequest().getParameter("previous.x");
			String lastPage = this.getRequest().getParameter("currentPage");
			if (lastPage != null) {
				int lastPageInt = Integer.parseInt(lastPage);
				log.info("lastPage = " + lastPage);
				if (nextButtonParam != null) {
					this.setCurrentPage(lastPageInt + 1);
				} else if (previousButtonParam != null) {
					this.setCurrentPage(lastPageInt - 1);
				} else {
					this.setCurrentPage(lastPageInt);
				}
			} else {
				log.info("Last page number not given, assuming page 0");
				this.setCurrentPage(0);
			}
			log.info("Adding table to form");
			form.addElement(mainTable);
			form.setMethod(Form.post);
			
			Input currentPageHidden = new Input();
			currentPageHidden.setType(Input.hidden);
			currentPageHidden.setName("currentPage");
			currentPageHidden.setValue("" + this.currentPage);
			log.info("Adding current page as a hidden to the form");
			form.addElement(currentPageHidden); 
			
		} else {
			String pageParam = this.getRequest().getParameter(PAGE_PARAM);
			int pageNumber = 0;
			if (pageParam != null) {
				pageNumber = Integer.parseInt(pageParam);
				setCurrentPage(pageNumber);
				log.debug("doStartTag() - page number = " + pageNumber);
			}
			else {
				log.debug("doStartTag() - page not specified, assuming it is 0");
				setCurrentPage(0);
			}
			
		}
		
		
		if (this.getWidth() != null) {
			mainTable.setWidth(this.getWidth());
		} else {
			mainTable.setWidth("80%");
		}
		
		Row mainRow = mainTable.addRow();
		Cell mainCell = mainRow.addCell();
		String topPageContent = getTopOfPageContent();
		//mainCell.addElement(topPageContent);

		log.debug("doStartTag() - getting current page from derived.");
		List elementList = null;
		

		int startElement = this.currentPage * this.getPageSize();
		int endElement = ((this.currentPage + 1) * this.getPageSize()) - 1;

		if (endElement > totalElementCount - 1) {
			endElement = totalElementCount - 1;
		}

		elementList = pageList.getElements(startElement, endElement);

		mainCell.addElement(this.makePageTopContent(getDescription()));
		if (this.usePageListing()) {
			if (this.showNextPrevAtTop) {
				log.debug("doStartTag() - Making previous and next page links");
				mainCell.addElement(makePrevNextLinks(form));
			} else {
				log.debug("Option to show prev next buttons at top is off");
			}
		}

		log.debug("doStartTag() - showing list of users");
		showList(getDescription(), mainCell, elementList, form);
		        
		Table bottomTable = new Table();
		mainCell.addElement(bottomTable);
		bottomTable.setWidth("100%");
		Row bottomRow = bottomTable.addRow();
		Cell leftBottomCell = bottomRow.addCell();
		Cell centerBottomCell = bottomRow.addCell();
		Cell rightBottomCell = bottomRow.addCell();
		
		if (this.usePageListing()) {
			log.debug("making prev/next links");
			rightBottomCell.addElement(makePrevNextLinks(form));
		}
		else {
			log.debug("this class doesn't use page listing, "
					+ "not making prev/next links");
		}
		     
		if (this.getTotalPages() > 0) {
			if (this.usePageListing()) {   
				centerBottomCell.addElement(TextHelper.getFont("stdFont", 
						this.getPhrase("phrase.page") + " " + (getCurrentPage() + 1) + " of " 
						+ this.getTotalPages()));
			}
		}
		else {
			String noElementsMessage = getNoElementsMessage();
			mainCell.addElement(TextHelper.getFont("stdFont", noElementsMessage));
		}
		
		fillBottomCell(leftBottomCell);
		
		log.debug("doStartTag() - writing");
		
		if (form != null) {
			return(form.toString());
		} else {
			return(mainTable.toString());
		}
	}


	protected String getPreviousFormButton() {
		StringBuffer html = new StringBuffer();
		html.append("<input type=\"image\" src=\"" +
				 this.getContextPath() + "/dynagraphic/button.jpg?code=button.ok&caption=" 
				+ this.getPhrase("button.previous") 
				+ "\" border=\"0\" value=\"previous\" name=\"previous\" />");
		return(html.toString());
	}
	
	protected String getNextFormButton() {
		StringBuffer html = new StringBuffer();
		html.append("<input type=\"image\" src=\"" +
				this.getContextPath() +  "/dynagraphic/button.jpg?code=button.ok&caption=" 
				+ this.getPhrase("button.next") 
				+ "\" border=\"0\" value=\"next\" name=\"next\" />");
		return(html.toString());
	}

	
	protected A getPageLink(int pageNumber, Form form) {
		log.debug("entering getPreviousLinkHtml()");
		A link = new A();
		if (form != null) {
			/*
			log.info("Page list have form, page links use form submit on click");
			link.setOnClick("submitForm('" + form.getAttribute("name") +
					"');");
					*/
		} else {
			link.setHref(getPageHref(pageNumber));
		}
		link.addElement("" + (pageNumber + 1));
		link.setClass("stdLink");
		return(link);
	}
	
	
	protected String getPreviousLinkHtml() {
		log.debug("entering getPreviousLinkHtml()");
		String html = null; 
		if (this.useGraphicButtons) {
			html = "<form name=\"PREV\" action=\"" + getPageListLink() 
							+ "\" method=\"POST\"" + ">\r\n";
			html += "\t<input type=\"hidden\" name=\"" + PAGE_PARAM
			+ "\" value=\"" +  (this.getCurrentPage() - 1) + "\">";
			html += "\t"; 
			html += "<input type=\"image\" src=\"" +
					this.getContextPath() + "/dynagraphic/button.jpg?code=button.param&caption=" 
			    	+ this.getPhrase("button.previous") + "\" border=\"0\" value=\"submit\" name=\"submit\" />";
			html += "</form>\r\n";
		} else {
			A link = new A();
			link.setHref(getPageHref(this.currentPage - 1));
			link.addElement("Previous");
			link.setClass("stdLink");
			html = link.toString();
		}
		return(html);
	}
	
	
	
	protected String getPageHref(int pageNumber) {
		String href = null;
		href = getPageListLink();
		if (href.indexOf("?") > 0) {
			href += "&" + PAGE_PARAM + "=" + pageNumber;
		} else {
			href += "?" + PAGE_PARAM + "=" + pageNumber;
		}
		return(href);
	}

	protected String getNextLinkHtml() {
		log.debug("entering getNextLinkHtml()");
		String html = null;
		if (this.useGraphicButtons) {
			html = "<form name=\"NEXT\" action=\"" + getPageListLink() + "\" method=\"POST\"" + ">\r\n";
			html += "\t<input type=\"hidden\" name=\"" + PAGE_PARAM
			+ "\" value=\"" +  (this.getCurrentPage() + 1) + "\">";
			html += "\t"; //<input type=\"submit\" name=\"submit\" value=\"Previous\" class=\"pageFormButton\">";
			html += "<input type=\"image\" src=\"" +
					this.getContextPath() + "dynagraphic/button.jpg?code=button.param&caption=" 
			    	+ this.getPhrase("button.next") + "\" border=\"0\" value=\"submit\" name=\"submit\" />";
			html += "</form>\r\n";
		} else {
			A link = new A();
			link.setHref(getPageHref(this.currentPage + 1));
			link.addElement("Next");
			link.setClass("stdLink");
			html = link.toString();
		}

		return(html);
	}
	
	

	protected final String makePrevNextLinks(Form form) {
		log.debug("entering makePrevNextLinks() - method to display links"
				+ " to the next and prev pages in the list");
		Table table = new Table();
		table.setCellPadding(1);
		table.setWidth("100%");

		if (this.getTotalPages() > 1) {
			Row row = table.addRow();
			Cell cell = row.addCell();
			cell.setWidth("90%");
	        
			cell = row.addCell();
			if (this.getCurrentPage() > 0) {
				log.debug("current page is greater than '0' - displaying previous link");
				String html = this.getPreviousLinkHtml();
				if (form != null)
					html = this.getPreviousFormButton();
				cell.addElement(html);
			}
			else {
				log.debug("current page is '0' - NOT displaying previous link");
				cell.setWidth(90);
			}
	
			log.debug("Display some exact page navs");
			int lastPage = this.getTotalPages() - 1;
			for (int i = 0; i <= lastPage; i++) {
				boolean displayPage = false;
				if (i < 3) 
					displayPage = true;
				else if ((currentPage - i <= 3) && (currentPage - i >= 0)) 
					displayPage = true;
				else if ((i - currentPage <= 3) && (i - currentPage >= 0))
					displayPage = true;
				else if ((lastPage - i <= 3) && (lastPage - i >= 0))
					displayPage = true;
				if (displayPage) {
					cell = row.addCell();
					if (i == this.getCurrentPage()) {
						cell.addText("stdFont", "" + (i + 1));
					} else {
						if (form == null) {
							A link = this.getPageLink(i, form);
							cell.addElement(link);
						} else {
							// Do not create page number links if form is created - simple links won't work for forms, because submission is
							// needed.
						}
					}
				}
			}
	
			if (hasNextPage()) {
				log.debug("this list has a next page - displaying 'next' link");
				String html = this.getNextLinkHtml();
				if (form != null)
					html = this.getNextFormButton();
				cell = row.addCell();
				cell.addElement(html);
	
			} else {
				log.debug("this list does NOT have a next page - NOT displaying 'next' link");
				cell.setWidth(90);
			}
		}
		return(table.toString());
	}


	/**
	 * @return Returns the showVoided.
	 */
	public boolean getShowVoided() {
		return showVoided;
	}

	/**
	 * @param showVoided The showVoided to set.
	 */
	public void setShowVoided(boolean showVoided) {
		this.showVoided = showVoided;
	}
	
	public String getWidth() {
		return width;
	}

	public void setWidth(String width) {
		this.width = width;
	}

}
